#include "PrecompiledHeaders.h"
#include "Clone.h"
#include "Constants.h"
#include "BodyType.h"

Ogre::SceneNode *Ogre::cloneSceneNode(Ogre::SceneNode *old_node, Ogre::String suffix)
{
    SceneManager *scene_mgr = old_node->getCreator();
    
    SceneNode *new_node = scene_mgr->createSceneNode(old_node->getName() + suffix);
    
    SceneNode::ObjectIterator obj = old_node->getAttachedObjectIterator();
    while( obj.hasMoreElements() )
    {
        MovableObject *child = obj.getNext();
        
        Entity *entity = dynamic_cast<Entity *>( child );
        
        if (entity != NULL) {
            Entity *new_entity = entity->clone(entity->getName() + suffix);
            
            for (unsigned i = 0; i < entity->getNumSubEntities(); i++)
            {
                SubEntity *sub_ent = entity->getSubEntity(i);
                SubEntity *new_sub_ent = new_entity->getSubEntity(i);
                MaterialPtr mat = sub_ent->getMaterial();
                String new_mat_name = mat->getName() + "_ghost";
                MaterialPtr new_mat = (Ogre::MaterialPtr) MaterialManager::getSingleton().getByName(new_mat_name);
                if (new_mat.isNull()) {
                    new_mat = makeGhostMaterial(mat, new_mat_name);
                }
                new_sub_ent->setMaterialName(new_mat_name);
                
            }
            
            new_node->attachObject(new_entity);
        }
    }
    
    SceneNode::ChildNodeIterator ch = old_node->getChildIterator();
        
    while( ch.hasMoreElements() )
    {
        Node *child = ch.getNext();
        
        SceneNode *child_sn = dynamic_cast<SceneNode *>( child );
        if (child_sn != NULL)
            new_node->addChild(cloneSceneNode(child_sn, suffix));
    }
    
    new_node->setPosition(old_node->getPosition());
    new_node->setOrientation(old_node->getOrientation());
    new_node->setScale(old_node->getScale());
    
    return new_node;
}

Ogre::MaterialPtr Ogre::makeGhostMaterial(Ogre::MaterialPtr mat, Ogre::String new_mat_name)
{
    MaterialPtr new_mat = mat->clone(new_mat_name);
    Material::TechniqueIterator t_it = new_mat->getTechniqueIterator();
    while( t_it.hasMoreElements() )
    {
        Technique *tech = t_it.getNext();
        Technique::PassIterator p_it = tech->getPassIterator();
        while( p_it.hasMoreElements() )
        {
            Ogre::Pass *pass = p_it.getNext();
            
            Ogre::ColourValue amb = pass->getAmbient();
            amb.a *= CLONED_ALPHA_FACTOR;
            pass->setAmbient(amb);
            
            Ogre::ColourValue diff = pass->getDiffuse();
            diff.a *= CLONED_ALPHA_FACTOR;
            pass->setDiffuse(diff);
            
            Ogre::ColourValue spec = pass->getSpecular();
            spec.a *= CLONED_ALPHA_FACTOR;
            pass->setSpecular(spec);
            //pass->setShininess(0);
            
            pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
            pass->setDepthWriteEnabled(false);
        }
    }
    return new_mat;
}

OgreNewt::Body *OgreNewt::cloneBody(OgreNewt::Body *old_body, Ogre::String suffix, int new_player_id)
{
    Ogre::SceneNode *old_node = dynamic_cast<Ogre::SceneNode*>(old_body->getOgreNode());
    if (!old_node)
        throw new Ogre::Exception(10002, "Body not attached to a scene node - can not clone", "Player::clone");
      
    Ogre::SceneNode *parent = old_node->getParentSceneNode();
    if (parent == NULL)
        throw new Ogre::Exception(10002, "Body attached to root scene node - can not clone", "Player::clone");
        
    Ogre::SceneNode *new_node = Ogre::cloneSceneNode(old_node, suffix);
    parent->addChild(new_node);
    
    BodyType new_bt(old_body->getType());
    new_bt.setPlayerID(new_player_id);
    OgreNewt::Body *new_body = new OgreNewt::Body(old_body->getWorld(), old_body->getCollision(), new_bt.getValue());
    
    Ogre::Vector3 pos; Ogre::Quaternion orient;
    old_body->getPositionOrientation( pos, orient );
    new_body->setPositionOrientation( pos, orient ); 

    Ogre::Real mass; Ogre::Vector3 inertia;
    old_body->getMassMatrix( mass, inertia );
    new_body->setMassMatrix( mass, inertia );
    
    new_body->attachToNode(new_node);

    return new_body;
    
}
